<?php
namespace control;

/*
*材料倒冲类
*/

class materialDistributeClass extends adIndexClass
{
    private const page = 'materialDistribute';
    private const table = 'material_distribute';//成本分摊主表
    private const table_num = 'material_distribute_num';//数量分配表
    private const table_source = 'material_distribute_source';//源单表
    private const table_detail = 'material_distribute_detail';//库存分配表
    private const title = '材料倒冲';
    public array $typeOption = [1 => '按BOM用量', 2 => '按待分配数量-差异均分', 3 => '按待分配数量-差异百分比'];//分配方式

    /*列表-查询条件*/
    public function home()
    {
        //返回
        return $this->edit();
    }

    /**
     * 保存并提交
     * @return bool|string
     */
    public function saveAndCommit(): bool|string
    {
        $resultJson = $this->editEdit();
        $result = json_decode($resultJson,true);
        if ($result['warn'] == 2){
            unset($_SESSION['warn']);
            $obj = new materialDistributeRecordClass();
            $resultJson = $obj->commitEdit();
        }
        return $resultJson;
    }
    /**
     * 编辑页
     * @return string
     */
    public function edit(): string
    {
        $id = suiji();
        $button[] = [
            'style' => 'li-btn-blue-bg',
            "name" => "保存",
            "type" => "点击事件",
            "title" => "保存",
            'fun' => "subForm('materialDistributeHomeForm','" . root . "control/adIndex.html?cla=" . self::page . "&fun=editEdit')"
        ];
        $button[] = [
            "name" => "保存并提交",
            "type" => "点击事件",
            "title" => "保存",
            'fun' => "subForm('" . self::page . "EditForm','" . root . "control/adIndex.html?cla=" . self::page . "&fun=saveAndCommit')"
        ];
        $tr[] = ['操作', '生产线', '存货类别', '物料编码', '物料名称', '规格型号', '单位', '库存数量', '实际BOM用量', '本次分配'];
        $total      = [
            8  => "<span id='bom_num'>0</span>",
            9  => "<span id='dis_num'>0</span>",
        ];
        $list = $this->listTable(array('tr' => $tr, 'end' => true, 'total' => $total));

        $sourceTr[] = ['操作', '单据日期', '单据编号', '加工类型', '生产线', '存货类别', '物料编码', '物料名称', '规格型号', '单位', '计划数量', '合格数量', '报废数量', 'BOM版本'];
        $total      = [
            10  => "<span id='plan_num'>0</span>",
            11  => "<span id='pass_num'>0</span>",
            12  => "<span id='scrap_num'>0</span>",
        ];
        $sourceList = $this->listTable(array('tr' => $sourceTr, 'end' => true, 'total' => $total));
        //源单
        $tableBut = <<<efo
                <span class="smallButton" onclick="chooseSourceOrder()">关联源单</span>
                <span class="smallButton" onclick="bom()">计算BOM</span>
efo;
        //线边库存选择
        $table2But = <<<efo
                <span class="smallButton" onclick="chooseInventory()">线边库存选择</span>
efo;
        //表单
        $data['button'] = $this->tableShowButton($button);
        $body = $this->edit4([
            '基本信息' => [
                [
                    must . "生产线：" => repeatSelect(array(
                            'name' => 'workshop',
                            'title' => '生产车间',
                            'change' => "getLine",
                            'sqlForm' => "product_line where coid = '" . self::$coid . "' and state = '启用'",
                            'sqlField' => 'workshop'
                        )) .
                        idSelect(array(
                            'name' => 'lineId',
                            'sqlForm' => "product_line where coid = '" . self::$coid . "' and state = '启用' and workshop = ''",
                            'sqlId' => 'id',
                            'sqlField' => 'name',
                            'title' => '生产线',
                        )),
                    must . "单据日期：" => text(["name" => "recordDate", 'laydate' => [], "value" => $this->date]),
                    must . "分配方式：" => radio(array('name' => 'type', 'value' => $this->typeOption, 'checked' => 1)),
                ],
            ]
        ]);
        $body .= $this->editList([
            'id' => 'orderTable',
            'title' => '源单据',
            'button' => $tableBut,
            'html' => $sourceList,
        ]);
        $body .= $this->editList([
            'id' => 'materialTable',
            'title' => '分配材料',
            'button' => $table2But,
            'html' => $list,
        ]);
        $data['html'] = $this->pageEdit([
            "html" => $body,
            'hidden' => hidden(['name' => 'id', 'value' => $id]),
        ]);
        $data['html'] .= $this->editJs();
        //返回
        return $this->tab($data);
    }

    private function editJs()
    {
        $cla = self::page;
        return <<<eof
<script>
function bom(){
    $.post(root+'control/adIndex.html?cla=$cla&fun=bom',$('form[name=materialDistributeHomeForm]').serialize(),function(res) {
      if (res.warn==2){
            $("#materialTable tbody").empty().append(res.html);
            resetNumber($("#materialTable"))
      }else{
          msg(res.warn,'error')
      }
    },'json')
}
function chooseInventory(){
     let lineId = $("[name='lineId']").val();
    if (!lineId){
        msg('请先选择生产线','error')
    }else{
        layer('$cla','addStock',$('form[name=materialDistributeHomeForm]').serialize())
    }
}
function chooseSourceOrder(){
    let lineId = $("[name='lineId']").val();
    if (!lineId){
        msg('请先选择生产线','error')
    }else{
        layer('$cla','addOrder',$('form[name=materialDistributeHomeForm]').serialize())
    }
}
//获取生产线
function getLine(e){
     let val = e.value;
     $.post(root+'control/adIndex.html?cla=machiningOrder&fun=getLine',{val:val},function(res) {
             $("select[name='lineId']").html(res.html);
        },'json');
}
function addOrder(){
     $.post(root+'control/adIndex.html?cla=$cla&fun=addOrderEdit',$("form[name='orderForm']").serialize(),function (res){
           $("#orderTable tbody").append(res.html);
           resetNumber($("#orderTable"))
           calculateTotal()
         },'json');
}
//计算计划数量
function calculateTotal(table=''){
    table = table ? table : $('.editList')
    let plan_num = 0,
    pass_num = 0,
    scrap_num = 0
    table.find(".plan_num").each(function(index){
        if($(this).text()){
          plan_num+=Number($(this).text());
        }
        var passNumText = table.find(".pass_num").eq(index).text()
        if(passNumText){
            pass_num+=Number(passNumText);
        }
        var scrapNumText = table.find(".scrap_num").eq(index).text()
        if(scrapNumText){
            scrap_num+=Number(scrapNumText);
        }
    })
    $("#plan_num").text(plan_num.toFixed(publicSettings.numPrecision.num));
    $("#pass_num").text(pass_num.toFixed(publicSettings.numPrecision.num));
    $("#scrap_num").text(scrap_num.toFixed(publicSettings.numPrecision.num));
}
function addStock(){
     $.post(root+'control/adIndex.html?cla=$cla&fun=addStockEdit',$("form[name='stockForm']").serialize(),function (res){
           $("#materialTable tbody").append(res.html);
           resetNumber($("#materialTable"))
           calculateInventoryTotal($('#materialTable'))
         },'json');
}
//计算计划数量
function calculateInventoryTotal(table=''){
    table = table ? table : $('.editList')
    let bom_num = 0,
    dis_num = 0
    table.find("[name='num[]']").each(function(index){
        if($(this).val()){
          dis_num+=Number($(this).val());
        }
        var bomNumText = table.find(".bom_num").eq(index).text()
        if(bomNumText){
            bom_num+=Number(bomNumText);
        }
    })
    $("#bom_num").text(bom_num.toFixed(publicSettings.numPrecision.num));
    $("#dis_num").text(dis_num.toFixed(amountPrecision));
}
</script>
eof;

    }


    /**
     * 计算BOM
     */
    public function bom()
    {
        $mxIdArr = $this->post('sourceId');
        $lineId = $this->post('lineId');
        $type = $this->post('type');
        if (static::is_null_array($mxIdArr)) {
            $json['warn'] = '请先选择单据';
        } elseif (empty($lineId)) {
            $json['warn'] = '请选择生产线';
        } elseif (empty($type)) {
            $json['warn'] = '请选择分配类型';
        } else {
            $json['html'] = '';
            $machiningOrderClass = new machiningOrderClass();
            $material_list = [];
            $bomAll = [];
            $all = find(array(
                'table' => 'machining_order_mx',
                "where" => "coid = '" . self::$coid . "' and id in ('" . implode("','", $mxIdArr) . "') order by list asc"
            ));
            foreach ($all['array'] as $array) {
                $machining_order = query('machining_order', "id = '$array[orderId]'");
                //在BOM表中找领料类型为配料的
                $result_list = machiningOrderClass::singleBomMx($array['bomId'], $array['materialId'], $array['num'], $array['unit']);
                $material_list = $machiningOrderClass->merge_material_two($material_list, $result_list);
                $bomArray = $machiningOrderClass->getFactMaterialNum($machining_order['id']);
                $bomAll = $machiningOrderClass->mergeBomArray($bomAll, $bomArray);
            }
            $bomAll = $machiningOrderClass->singleBomArray($bomAll);
            $tr = [];
            foreach ($material_list as $k=>$array) {
                $line = query('product_line', "id = '$lineId'");
                $material = query('material', "id = '$array[materialId]'");
                if (!empty($material['id'])) {
                    $uid = self::getId();
                    $stockNum = tempInventoryClass::inventoryNum($array['materialId'], $material['unit'], $line['id']);
                    $bomNum = isset($bomAll[$array['materialId']]) ? self::lostZero($bomAll[$array['materialId']], 'numPrecision') : 0;
                    $disNum = match ($type) {
                        '1' => $bomNum,
                        '2', '3' => $stockNum,
                        default => '',
                    };
                    $tr[] = [
                        componentClass::tablePperation($k+1,'delTableRow(this);calculateInventoryTotal($("#materialTable"))').
                        hidden(array('name' => 'detailId[]', 'value' => $uid)) .
                        hidden(array('name' => 'materialId[]', 'value' => $array['materialId'])),
                        $line['workshop'] . '-' . $line['name'],
                        $material['subject'],
                        $material['code'],
                        $material['name'],
                        $material['model'],
                        $material['unit'],
                        $stockNum,
                        "<span class='bom_num'>{$bomNum}</span>",
                        text(array('name' => 'num[]', 'other' => self::digitalFiltering('numPrecision')." onblur=\"calculateInventoryTotal($('#materialTable'))\" ", 'value' => $disNum))
                    ];
                }
            }
            if (empty($tr)){
                $json['warn'] = "未通过BOM找到所需材料";
            }else{
                $json['html'] = $this->tableMany(['tr' => $tr, 'thead' => false]);
                $json['warn'] = 2;
            }

        }
        return json_encode($json, 320);
    }


    public function editEdit()
    {
        $id = $this->post('id') ?: self::getId();
        //源单
        $mxIdArr = $this->post('mxId') ?: [];
        $sourceIdArr = $this->post('sourceId');

        //分配材料
        $detailIdIdArr = $this->post('detailId') ?: [];
        $numArr = $this->post('num');
        $materialIdArr = $this->post('materialId');

        $field = [
            'lineId' => $this->post('lineId'),
            'type' => $this->post('type'),
            'recordDate' => $this->post('recordDate'),
        ];
        $annotation = [
            'lineId' => '生产线',
            'type' => '分配方式',
            'recordDate' => '单据日期',
        ];
        $rules = [
            'lineId' => 'required',
            'type' => 'required',
            'recordDate' => 'required',
        ];
        // 校验是否符合规则
        $vt = new \verify();
        $result = $vt->setAliases($annotation)->validate($field, $rules)->isOk();
        if ($result === false) {
            $json['warn'] = $vt->getErrs()[0];  // 多个规则提示最前面一条
            goto resp;
        }
        $where = " id = '$id' ";
        $info = query(self::table, $where);
        //判断
        if (!$this->power(self::page, "edit")) {
            $json['warn'] = "你没有编辑" . self::title . "的权限";
        } elseif (static::is_null_array($mxIdArr)) {
            $json['warn'] = '请选择源单';
        } elseif (static::is_null_array($sourceIdArr)) {
            $json['warn'] = '请选择源单';
        } elseif (static::is_null_array($detailIdIdArr)) {
            $json['warn'] = '请选择需要分配的材料';
        } elseif (static::is_null_array($materialIdArr)) {
            $json['warn'] = '请选择需要分配的材料';
        } elseif (static::is_null_array($numArr)) {
            $json['warn'] = '请填写数量';
        } else {
            $this->startTrans();
            if (!$info['id']) {
                $userNo = codeTemplateClass::generateCode(self::page, [
                    'prefix' => 'CLFP' . date('Ymd', strtotime($field['recordDate'])),
                    'table' => self::table,
                    'field' => 'orderNo',
                    'where' => " and coid = '" . self::$coid . "'",
                ], $field);
                $field = array_merge($field, [
                    'id' => $id,
                    'orderNo' => $userNo,
                    'state' => '草稿',
                    'coid' => self::$coid,
                    'stid' => $this->control['stid'],
                ]);
                $json['warn'] = static::insert(["table" => self::table, "field" => $field]);
            } else {
                $json['warn'] = static::update([
                    "table" => self::table,
                    "field" => $field,
                    "where" => $where
                ]);
            }

            //源单
            foreach ($mxIdArr as $k => $nid) {
                $mx = query(self::table_source, "id = '$nid'");
                $machiningOrderMx = query('machining_order_mx', "id = '$sourceIdArr[$k]'");
                $machiningOrder = query('machining_order', "id = '$machiningOrderMx[orderId]'");
                if (!empty($mx['id'])) {
                    //更新
                    $warn = static::update([
                        "table" => self::table_source,
                        "field" => [
                            'machiningOrderMxId' => $sourceIdArr[$k],
                            'machiningOrderId' => $machiningOrder['id'],
                            'sourceType' => $machiningOrder['orderType'],
                        ],
                        "where" => " id = '$nid'"
                    ]);
                } else {
                    //新增
                    $warn = static::insert([
                        "table" => self::table_source,
                        "field" => [
                            'id' => $nid,
                            'orderId' => $id,
                            'coid' => self::$coid,
                            'machiningOrderMxId' => $sourceIdArr[$k],
                            'machiningOrderId' => $machiningOrder['id'],
                            'sourceType' => $machiningOrder['orderType'],
                        ],
                    ]);
                }
                if (!in_array($warn, ['新增成功', '更新成功'])) {
                    $json['warn'] = $warn;
                    break;
                }
            }

            foreach ($detailIdIdArr as $k => $mxId) {
                $mx = query(self::table_detail, "id = '$mxId'");
                $material = query('material', "id = '$materialIdArr[$k]'");
                $numArr[$k] = self::formattingFigure($numArr[$k], 'numPrecision');
                if (!empty($mx['id'])) {
                    //更新
                    $warn = static::update([
                        "table" => self::table_detail,
                        "field" => [
                            'materialId' => $material['id'],
                            'unit' => $material['unit'],
                            'num' => $numArr[$k],
                        ],
                        "where" => " id = '$mxId'"
                    ]);
                } else {
                    //新增
                    $warn = static::insert([
                        "table" => self::table_detail,
                        "field" => [
                            'id' => $mxId,
                            'orderId' => $id,
                            'coid' => self::$coid,
                            'materialId' => $material['id'],
                            'unit' => $material['unit'],
                            'num' => $numArr[$k],
                        ],
                    ]);
                }
                if (!in_array($warn, ['新增成功', '更新成功'])) {
                    $json['warn'] = $warn;
                    break;
                }
            }

            if (in_array($json['warn'], ["新增成功", "更新成功"])) {
                delete(array('table' => self::table_detail, 'where' => " id not in ('" . implode("','", $detailIdIdArr) . "') and orderId = '$id'"));
                delete(array('table' => self::table_source, 'where' => " id not in ('" . implode("','", $mxIdArr) . "') and orderId = '$id'"));
                delete(array('table' => self::table_num, 'where' => "orderId = '$id'"));
                $this->commitTrans();
                //数量分配
                $bool = $this->numDis($field['type'], $id);
                if ($bool !== true) {
                    $json['warn'] = $bool;
                    delete(array('table' => self::table_detail, 'where' => "orderId = '$id'"));
                    delete(array('table' => self::table_source, 'where' => "orderId = '$id'"));
                    delete(array('table' => self::table, 'where' => "id = '$id'"));
                } else {
                    if ($json['warn'] == '新增成功') {
                        auditingFollow(array(
                            "type" => "材料分配记录",
                            "typeId" => $id,
                            "text" => "【{$this->control['name']}】新增",
                            'job' => self::findStaffDepartment(self::$stid) . '-' . $this->controlJob['name'],
                            'staffName' => $this->control['name'],
                        ));
                    }
                    //添加日志
                    $type = mb_substr($json['warn'], 0, 2, 'utf-8');
                    $text = $this->control['name'] . $type . "了" . self::title . " id：【" . $id . '】';
                    $this->logText(["type" => self::page, "text" => $text]);
                    //返回
                    $_SESSION['warn'] = $json['warn'];
                    $json['warn'] = 2;
                }

            } else {
                $this->rollback();
            }
        }

        resp:
        return json_encode($json, 320);
    }

    /**
     * 数量分配
     */
    public function numDis($type, $id): bool|string
    {
        return match ($type) {
            '1' => $this->bomDis($id),//按BOM用量
            '2' => $this->averageDis($id),//按待分配数量-差异均分
            '3' => $this->percentDis($id),//按待分配数量-差异百分比
            default => '未找到分配类型'
        };
    }

    //按待分配数量-差异百分比
    private function percentDis($id): bool|string
    {
        $info = query(self::table, "id = '$id'");
        $machiningOrderClass = new machiningOrderClass();
        $sourceTemp = [];//每个源单所包含的物料
        $material_list = [];
        $all = find(array('table' => self::table_source, "where" => "orderId = '$info[id]' order by list asc"));
        foreach ($all['array'] as $array) {
            $machiningOrderMx = query('machining_order_mx', "id = '$array[machiningOrderMxId]'");
            $material = query('material', "id = '$machiningOrderMx[materialId]'");
            $result_list = machiningOrderClass::singleBomMx($machiningOrderMx['bomId'], $machiningOrderMx['materialId'], $machiningOrderMx['num'], $material['unit']);
            $sourceTemp[$array['id']] = $result_list;
            $material_list = $machiningOrderClass->merge_material_two($material_list, $result_list);
        }
        //材料分配
        $all = find(array('table' => self::table_detail, "where" => "orderId = '$info[id]' order by list asc"));
        foreach ($all['array'] as $array) {
            //此物料线边库存
            $stockNum = tempInventoryClass::inventoryNum($array['materialId'], $array['unit'], $info['lineId']);
            $material = query('material', "id = '$array[materialId]'");
            $productAll = find(array('table' => self::table_source, "where" => "orderId = '$info[id]' order by list asc"));
            $num = 0;//整个bom所需此物料数量
            $countArr = [];//包含此物料的产品单据ID;
            foreach ($productAll['array'] as $sourceArray) {
                //此单据此产品的所需此物料数量
                foreach ($sourceTemp[$sourceArray['id']] as $bomMx) {
                    //当前BOM层级所需的所有物料
                    if ($array['materialId'] == $bomMx['materialId']) {
                        $num += $bomMx['num'];
                        $countArr[] = $sourceArray['id'];
                    }
                }
            }
            $remindNum = $stockNum - $num;//库存减去需要的所剩余数
            foreach ($countArr as $sourceId) {
                $detail = query(self::table_source, "id = '$sourceId'");
                //此单据此产品的所需此物料数量
                $materialNum = 0;
                foreach ($sourceTemp[$sourceId] as $bomMx) {
                    //当前BOM层级所需的所有物料
                    if ($array['materialId'] == $bomMx['materialId']) {
                        $materialNum += $bomMx['num'];
                    }
                }
                $warn = static::insert(array(
                    'table' => self::table_num,
                    'field' => [
                        'id' => suiji(),
                        'coid' => self::$coid,
                        'orderId' => $id,
                        'sourceId' => $sourceId,
                        'machiningOrderId' => $detail['machiningOrderId'],
                        'machiningOrderMxId' => $detail['machiningOrderMxId'],
                        'materialId' => $material['id'],
                        'unit' => $material['unit'],
                        'num' => self::formattingFigure($materialNum + $remindNum * ($materialNum / $num), 'numPrecision'),
                    ]
                ));
                if ($warn != '新增成功') {
                    return '分配失败';
                }
            }
        }
        return true;
    }

    //按待分配数量-差异均分
    private function averageDis($id): bool|string
    {
        $info = query(self::table, "id = '$id'");
        $machiningOrderClass = new machiningOrderClass();
        $sourceTemp = [];//每个源单所包含的物料
        $material_list = [];
        $all = find(array('table' => self::table_source, "where" => "orderId = '$info[id]' order by list asc"));
        foreach ($all['array'] as $array) {
            $machiningOrderMx = query('machining_order_mx', "id = '$array[machiningOrderMxId]'");
            $material = query('material', "id = '$machiningOrderMx[materialId]'");
            $result_list = machiningOrderClass::singleBomMx($machiningOrderMx['bomId'], $machiningOrderMx['materialId'], $machiningOrderMx['num'], $material['unit']);
            $sourceTemp[$array['id']] = $result_list;
            $material_list = $machiningOrderClass->merge_material_two($material_list, $result_list);
        }
        //材料分配
        $all = find(array('table' => self::table_detail, "where" => "orderId = '$info[id]' order by list asc"));
        foreach ($all['array'] as $array) {
            //此物料线边库存
            $stockNum = tempInventoryClass::inventoryNum($array['materialId'], $array['unit'], $info['lineId']);
            $material = query('material', "id = '$array[materialId]'");
            $productAll = find(array('table' => self::table_source, "where" => "orderId = '$info[id]' order by list asc"));
            $num = 0;
            $countArr = [];//包含此物料的产品单据ID;
            foreach ($productAll['array'] as $sourceArray) {
                //此单据此产品的所需此物料数量
                foreach ($sourceTemp[$sourceArray['id']] as $bomMx) {
                    //当前BOM层级所需的所有物料
                    if ($array['materialId'] == $bomMx['materialId']) {
                        $num += $bomMx['num'];
                        $countArr[] = $sourceArray['id'];
                    }
                }
            }
            $coutNum = count($countArr);
            //如果除不尽，则把多余的加到第一条单据上
            $moreNum = 0;//除不尽多出来的数量
            if ($coutNum > 0 && ($stockNum - $num) % $coutNum != 0) {
                $moreNum = ($stockNum - $num) % $coutNum;
            }

            $perNum = $coutNum > 0 ? ($stockNum - $num - $moreNum) / $coutNum : 0;//每个产品此物料所需数量需要加的均分数量
            foreach ($countArr as $index => $sourceId) {
                $detail = query(self::table_source, "id = '$sourceId'");
                //此单据此产品的所需此物料数量
                $materialNum = 0;
                foreach ($sourceTemp[$sourceId] as $bomMx) {
                    //当前BOM层级所需的所有物料
                    if ($array['materialId'] == $bomMx['materialId']) {
                        $materialNum += $bomMx['num'];
                    }
                }
                if ($index > 0) {
                    //如果除不尽，则把多余的加到第一条单据上
                    $moreNum = 0;
                }
                $warn = static::insert(array(
                    'table' => self::table_num,
                    'field' => [
                        'id' => suiji(),
                        'coid' => self::$coid,
                        'orderId' => $id,
                        'sourceId' => $sourceId,
                        'machiningOrderId' => $detail['machiningOrderMxId'],
                        'machiningOrderMxId' => $detail['machiningOrderMxId'],
                        'materialId' => $material['id'],
                        'unit' => $material['unit'],
                        'num' => self::formattingFigure($materialNum + $perNum + $moreNum, 'numPrecision'),
                    ]
                ));
                if ($warn != '新增成功') {
                    return '分配失败';
                }
            }
        }
        return true;
    }

    //按BOM用量
    private function bomDis($id): bool|string
    {
        $info = query(self::table, "id = '$id'");
        $machiningOrderClass = new machiningOrderClass();
        $sourceTemp = [];//每个源单所包含的物料
        $material_list = [];
        $all = find(array('table' => self::table_source, "where" => "orderId = '$info[id]' order by list asc"));
        foreach ($all['array'] as $array) {
            $machiningOrderMx = query('machining_order_mx', "id = '$array[machiningOrderMxId]'");
            $material = query('material', "id = '$machiningOrderMx[materialId]'");
            $result_list = machiningOrderClass::singleBomMx($machiningOrderMx['bomId'], $machiningOrderMx['materialId'], $machiningOrderMx['num'], $material['unit']);
            $sourceTemp[$array['id']] = $result_list;
            $material_list = $machiningOrderClass->merge_material_two($material_list, $result_list);
        }

        //材料分配
        $all = find(array('table' => self::table_detail, "where" => "orderId = '$info[id]' order by list asc"));
        foreach ($all['array'] as $array) {
            $material = query('material', "id = '$array[materialId]'");
            $productAll = find(array('table' => self::table_source, "where" => "orderId = '$info[id]' order by list asc"));
            foreach ($productAll['array'] as $sourceArray) {
                //已分配给此单据此产品的物料数量
                //$disNum = find(array('table'=>self::table_num,'where'=>"sourceId = '$sourceId' and coid = '".self::$coid."'",'sum'=>'num'));
                $num = 0;
                //此单据此产品的所需此物料BOM所占比例
                foreach ($sourceTemp[$sourceArray['id']] as $bomMx) {
                    //当前BOM层级所需的所有物料
                    if ($array['materialId'] == $bomMx['materialId']) {
                        $num += $bomMx['num'];
                    }
                }
                $totalNum = 0;
                //所有单据使用的此物料数量
                foreach ($material_list as $mx) {
                    if ($array['materialId'] == $mx['materialId']) {
                        $totalNum += $mx['num'];
                    }
                }
                $machiningOrderMx = query('machining_order_mx', "id = '$sourceArray[machiningOrderMxId]'");
                $warn = static::insert(array(
                    'table' => self::table_num,
                    'field' => [
                        'id' => suiji(),
                        'coid' => self::$coid,
                        'orderId' => $id,
                        'sourceId' => $sourceArray['id'],
                        'machiningOrderId' => $machiningOrderMx['orderId'],
                        'machiningOrderMxId' => $sourceArray['machiningOrderMxId'],
                        'materialId' => $material['id'],
                        'unit' => $material['unit'],
                        'num' => $totalNum > 0 ? self::formattingFigure($array['num'] * $num / $totalNum, 'numPrecision') : 0,
                    ]
                ));
                if ($warn != '新增成功') {
                    return '分配失败';
                }
            }
        }
        return true;
    }

    /**
     * 选择线边库存
     * @return bool|string
     */
    public function addStock(): bool|string
    {
        $layerId          = $this->get('cla') . ucwords($this->get('fun'));
        $materialClass = new materialClass();
        $html =
            text(array("name" => "code", "title" => "物料编码")) .
            text(array("name" => "materialName", "title" => "物料名称")) .
            text(array("name" => "model", "title" => "规格型号")) .
            select(array('name' => 'materialType', 'title' => '存货类别', 'option' => $materialClass->checkOption)) .
            hidden(array('name' => 'id', 'value' => $this->post('id'))) .
            hidden(array('name' => 'machiningOrderMxId', 'value' => $this->post('sourceId') ? implode(',', $this->post('sourceId')) : '')) .
            hidden(array('name' => 'lineId', 'value' => $this->post('lineId'))) .
            hidden(array('name' => 'sourceId', 'value' => $this->post('materialId') ? implode(',', $this->post('materialId')) : ''));
        $button = "<input onclick=\"addStock();$('#" . $layerId . "').remove()\" type='button' class='searchSub m-l-5' value='提交'>";
        $html = $this->search($html);
        return $this->layer(array("title" => "添加", "height" => 600, "width" => 1100, "html" => $html, "button" => $button));
    }

    /**
     * 选择线边库存
     * @return bool|string
     */
    public function addStockSearch(): bool|string
    {
        $sourceId = $this->post('sourceId') ? explode(',', $this->post('sourceId')) : [];
        $and = " and a.materialId not in ('" . implode("','", $sourceId) . "')";

        $like = [
            'b.code' => $this->post('code'),
            'b.name' => $this->post('materialName'),
            'b.model' => $this->post('model'),
        ];
        $equal = [
            'b.subject' => $this->post('materialType'),
            'a.coid' => self::$coid,
            'a.lineId' => $this->post('lineId'),
        ];
        $where = search(["like" => $like, "=" => $equal]) . $and;

        $page = $this->page([
            "table" => 'line_inventory as a join material as b on a.materialId = b.id',
            'field' => "materialId,lineId,any_value(b.code) as code,any_value(b.name) as name,any_value(b.model) as model,any_value(b.unit) as unit,any_value(b.subject) as subject,ifnull(sum(any_value(a.num)),0) as num",
            "where" => $where . ' group by lineId,materialId'
        ]);
        //获取表头
        $checkAll = $this->checkAll("stockForm", "orderId");
        $tr[] = [$checkAll, '生产线', '存货类别', '物料编码', '物料名称', '规格型号', '单位', '当前库存数量'];
        //获取记录
        foreach ($page['array'] as $array) {
            $dominate = array(
                "box" => array("name" => "orderId", "value" => $array['materialId']),
            );
            $line = query('product_line', " id = '$array[lineId]'");
            $tr[] = array(
                $this->dominate($dominate),
                $line['workshop'] . $line['name'], $array['subject'], $array['code'], $array['name'], $array['model'], $array['unit'], self::lostZero($array['num'], 'numPrecision')
            );
        }
        $json['html'] = $page['hint'] .
            "<form name='stockForm'>" .
                hidden(array('name' => 'lineId', 'value' => $this->post('lineId'))) .
                hidden(array('name' => 'machiningOrderMxId', 'value' => $this->post('machiningOrderMxId'))) .
                $this->tableMany(array("tr" => $tr, "showSort" => true, "page" => $page['para'])) .
            "</form>" .
            $page['button'];
        return json_encode($json, 320);
    }

    /**
     * 选择线边库存
     */
    public function addStockEdit(): bool|string
    {
        $mxIdArr = $this->post('orderId');
        $lineId = $this->post('lineId');
        $machiningOrderMxId = $this->post('machiningOrderMxId') ? explode(',', $this->post('machiningOrderMxId')) : [];
        if (!$this->power(self::page, 'edit')) {
            $json['warn'] = '你还没有编辑权限';
        } elseif (empty($mxIdArr) || !is_array($mxIdArr)) {
            $json['warn'] = '请选择物料';
        } elseif (empty($lineId)) {
            $json['warn'] = '未找到生产线ID';
        } elseif (empty($machiningOrderMxId)) {
            $json['warn'] = '请先选择源单据';
        } else {
            $tr = [];
            $machiningOrderClass = new machiningOrderClass();
            $material_list = [];
            $bomAll = [];
            $all = find(array(
                'table' => 'machining_order_mx',
                "where" => "coid = '" . self::$coid . "' and id in ('" . implode("','", $machiningOrderMxId) . "') order by list asc"
            ));
            foreach ($all['array'] as $array) {
                $machining_order = query('machining_order', "id = '$array[orderId]'");
                $result_list = machiningOrderClass::singleBomMx($array['bomId'], $array['materialId'], $array['num'], $array['unit']);
                $material_list = $machiningOrderClass->merge_material_two($material_list, $result_list);
                $bomArray = $machiningOrderClass->getFactMaterialNum($machining_order['id']);
                $bomAll = $machiningOrderClass->mergeBomArray($bomAll, $bomArray);
            }
            $bomAll = $machiningOrderClass->singleBomArray($bomAll);
            foreach ($mxIdArr as $id) {
                $line = query('product_line', "id = '$lineId'");
                $material = query('material', "id = '$id'");
                $uid = self::getId();
                $stockNum = tempInventoryClass::inventoryNum($id, $material['unit'], $line['id']);
                $bomNum = isset($bomAll[$material['id']]) ? self::lostZero($bomAll[$material['id']], 'numPrecision') : 0;
                $tr[] = [
                    componentClass::tablePperation('','delTableRow(this);calculateInventoryTotal($("#materialTable"))').
                    hidden(array('name' => 'detailId[]', 'value' => $uid)) .
                    hidden(array('name' => 'materialId[]', 'value' =>$id)),
                    $line['workshop'] . '-' . $line['name'],
                    $material['subject'],
                    $material['code'],
                    $material['name'],
                    $material['model'],
                    $material['unit'],
                    $stockNum,
                    "<span class='bom_num'>{$bomNum}</span>",
                    text(array('name' => 'num[]', 'other' => self::digitalFiltering('numPrecision')." onblur=\"calculateInventoryTotal($('#materialTable'))\" ", 'value' => $bomNum))
                ];
            }
            $json['warn'] = 2;
            $json['html'] = $this->tableMany(['tr'=>$tr,'thead'=>false]);
        }
        return json_encode($json, 320);
    }


    /**
     * 关联源单
     * @return bool|string
     */
    public function addOrder(): bool|string
    {
        $layerId          = $this->get('cla') . ucwords($this->get('fun'));
        $html =
            select(array("name" => "orderType", "title" => "源单类型", 'option' => ['生产计划' => '生产计划单', '半成品' => '半成品加工单'])) .
            text(array("name" => "orderNo", "title" => "源单编号")) .
            text(array("name" => "recordDate", 'class' => 'width200', 'laydate' => ['type' => 'date', 'range' => '~'], "title" => "单据日期-单据日期")) .
            hidden(array('name' => 'id', 'value' => $this->post('id'))) .
            hidden(array('name' => 'lineId', 'value' => $this->post('lineId'))) .
            hidden(array('name' => 'sourceId', 'value' => $this->post('sourceId') ? implode(',', $this->post('sourceId')) : ''));
        $button = "<input onclick=\"addOrder();$('#" . $layerId . "').remove()\" type='button' class='searchSub m-l-5' value='提交'>";
        $html = $this->search($html);
        return $this->layer(array("title" => "添加", "height" => 600, "width" => 1100, "html" => $html, "button" => $button));
    }

    /**
     * 关联源单
     * @return bool|string
     */
    public function addOrderSearch(): bool|string
    {
        $sourceId = $this->post('sourceId') ? explode(',', $this->post('sourceId')) : [];
        $where = "a.id not in ('" . implode("','", $sourceId) . "')";
        $and = '';
        $like = [
            'b.orderNo' => $this->post('orderNo'),
        ];
        $equal = [
            'b.state' => '已确认',
            'b.orderType' => $this->post('orderType'),
            'a.coid' => self::$coid,
            'b.lineId' => $this->post('lineId'),
        ];
        if ($this->post('recordDate')) {
            //单据日期
            $and .= self::timeComparison($this->post('recordDate'), 'date', 'recordDate');
        }
        $where .= search(["like" => $like, "=" => $equal]) . $and;

        $page = $this->page([
            "table" => "machining_order_mx as a join machining_order as b on a.orderId = b.id",
            'field' => 'a.*,b.orderType,b.orderNo,b.recordDate,b.lineId',
            "where" => $where,
            'pageNum' => 50,
            "order" => "b.recordDate desc,b.orderNo desc,a.list asc",
        ]);
        //获取表头
        $checkAll = $this->checkAll("orderForm", "orderId");
        $tr[] = [$checkAll, '源单类型', '源单编号', '单据日期', '生产线', '存货类别', '物料编码', '物料名称', '规格型号', '单位'];
        //获取记录
        foreach ($page['array'] as $array) {
            $dominate = array(
                "box" => array("name" => "orderId", "value" => $array['id']),
            );
            $material = query('material', "id = '$array[materialId]'");
            $line = query('product_line', "id = '$array[lineId]'");
            $tr[] = array(
                $this->dominate($dominate),
                $array['orderType'] == '生产计划' ? '生产计划单' : '半成品加工单',
                $array['orderNo'],
                $array['recordDate'],
                $line['workshop'] . '-' . $line['name'],
                $material['subject'],
                $material['code'],
                $material['name'],
                $material['model'],
                $array['unit']
            );
        }
        $json['html'] = $page['hint'] .
            "<form name='orderForm'>" .
                hidden(array('name' => 'id', 'value' => $this->post('id'))) .
                space .
                $this->tableMany(array("tr" => $tr, "showSort" => true, "page" => $page['para'])) .
            "</form>" .
            $page['button'];
        return json_encode($json, 320);
    }

    /**
     * 关联源单
     */
    public function addOrderEdit(): bool|string
    {
        $mxIdArr = $this->post('orderId');
        if (!$this->power(self::page, 'edit')) {
            $json['warn'] = '你还没有编辑权限';
        } elseif (empty($mxIdArr) || !is_array($mxIdArr)) {
            $json['warn'] = '请选择源单';
        } else {
            $tr=[];
            $costAllocation = new costAllocationClass();
            foreach ($mxIdArr as $id) {
                $machining_order_mx = query('machining_order_mx', "id = '$id'");
                $machining_order = query('machining_order', "id = '$machining_order_mx[orderId]'");
                $line = query('product_line', "id = '$machining_order[lineId]'");
                $material = query('material', "id = '$machining_order_mx[materialId]'");
                $bom = query('bom', "id = '$machining_order_mx[bomId]'");
                $uid = self::getId();
                $passNum = $costAllocation->getMaterialNum($machining_order_mx['id'], $machining_order_mx['unit']);
                $scrapNum = $costAllocation->getMaterialNum($machining_order_mx['id'], $machining_order_mx['unit'], '报废');
                $machining_order_mx['num'] = self::lostZero($machining_order_mx['num'], 'numPrecision');
                $tr[] = [
                    componentClass::tablePperation('',"delTableRow(this);calculateTotal()").
                    hidden(array('name' => 'mxId[]', 'value' => $uid)) .
                    hidden(array('name' => 'sourceId[]', 'value' =>$id)),
                    $machining_order['recordDate'],
                    $machining_order['orderNo'],
                    machiningInOrderClass::orderType($machining_order['orderType']),
                    $line['workshop'].'-'.$line['name'],
                    $material['subject'],
                    $material['code'],
                    $material['name'],
                    $material['model'],
                    $machining_order_mx['unit'],
                    "<span class='plan_num'>".$machining_order_mx['num']."</span>",
                    "<span class='pass_num'>".$passNum."</span>",
                    "<span class='scrap_num'>".$scrapNum."</span>",
                    $bom['bomVersion']?:'-'
                ];
            }
            $json['warn'] = 2;
            $json['html'] = $this->tableMany(['tr'=>$tr,'thead'=>false]);
        }
        return json_encode($json, 320);
    }

    /**
     * 计算成本均价
     * id  生产加工单ID/半成品加工单ID
     *
     */
    public static function avgInventoryPrice($id, $time = ''): bool|string
    {
        $cost = new costCountClass();
        $all = find(array('table' => 'machining_order_mx as a join machining_order as b on a.orderId = b.id', 'field' => "a.*", 'where' => "b.id = '$id'"));
        foreach ($all['array'] as $machiningOrderMx) {
            $result = $cost->inFee($machiningOrderMx['id']);
            $peopleFee = $cost->peopleFee($machiningOrderMx['id']);
            $materialFee = $cost->materialFee($machiningOrderMx['id']);
            $costTotal = $peopleFee + $materialFee + $result['money'];
            $num = $result['num'] > 0 ? $result['num'] : 0;
            $material = query('material', "id = '$machiningOrderMx[unit]'");
            $num = machiningOrderClass::material_num_change($machiningOrderMx['materialId'], $machiningOrderMx['unit'], $material['unit'], $num);
            $price = $num > 0 ? self::formattingFigure($costTotal / $num, 'pricePrecision') : 0;//成本单价

            if ($machiningOrderMx['sourceTable'] == 'product_demands') {
                $productDemand = query('product_demands', "id = '$machiningOrderMx[sourceId]'");
                $sale_order = query('sale_order', "id = '$productDemand[sourceId]'");
                $time = $time?:$sale_order['recordDate'];
            } elseif ($machiningOrderMx['sourceTable'] == 'sale_refund_order_detail') {
                $saleRefundOrderMx = query('sale_refund_order_detail', "id = '$machiningOrderMx[sourceId]'");
                $saleRefundOrder = query('sale_refund_order', "id = '$saleRefundOrderMx[orderId]'");
                $time = $time?:$saleRefundOrder['recordDate'];
            } elseif ($machiningOrderMx['sourceTable'] == 'sale_order_detail') {
                $saleOrderMx = query('sale_order_detail', "id = '$machiningOrderMx[sourceId]'");
                $saleOrder = query('sale_order', "id = '$saleOrderMx[orderId]'");
                $time = $time?:$saleOrder['recordDate'];
            } elseif ($machiningOrderMx['sourceTable'] == 'sale_forecast_detail') {
                $saleOrderMx = query('sale_forecast_detail', "id = '$machiningOrderMx[sourceId]'");
                $saleOrder = query('sale_forecast', "id = '$saleOrderMx[orderId]'");
                $time = $time?:$saleOrder['recordDate'];
            }

            $warn = inventoryDefaultClass::recordInventoryPrice($machiningOrderMx['materialId'], $num, $price, $time);
            if ($warn != '新增成功') {
                return '计算均价失败';
            }
        }
        return true;
    }
}

